﻿namespace FiftyOne.Foundation.Mobile.Detection
{
    using FiftyOne;
    using FiftyOne.Foundation.Mobile;
    using FiftyOne.Foundation.Mobile.Configuration;
    using System;
    using System.Collections.Generic;
    using System.Security;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Web;
    using System.Web.Configuration;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.MobileControls;

    public class DetectorModule : IHttpModule
    {
        private SortedList<string, string> _clientTargets = null;
        private bool _firstRequestOnly = true;
        private string _formsLoginUrl = null;
        private string _mobileHomePageUrl = null;
        private Regex _mobilePageRegex = null;
        private static readonly string[] MOBILE_PAGES = new string[] { "System.Web.UI.MobileControls.MobilePage" };
        private static readonly string[] PAGES = new string[] { "System.Web.UI.MobileControls.MobilePage", "System.Web.UI.Page" };

        public void Dispose()
        {
            EventLog.Debug("Disposing Detector Module");
        }

        private SortedList<string, string> GetClientTargets()
        {
            try
            {
                ClientTargetSection clientTargetsSection = this.GetClientTargetsSection();
                if (clientTargetsSection != null)
                {
                    SortedList<string, string> list = new SortedList<string, string>();
                    for (int i = 0; i < clientTargetsSection.ClientTargets.Count; i++)
                    {
                        list.Add(clientTargetsSection.ClientTargets[i].Alias, clientTargetsSection.ClientTargets[i].UserAgent);
                    }
                    return list;
                }
            }
            catch (SecurityException)
            {
                return null;
            }
            return null;
        }

        private ClientTargetSection GetClientTargetsSection()
        {
            return (WebConfigurationManager.GetWebApplicationSection("system.web/clientTarget") as ClientTargetSection);
        }

        public void Init(HttpApplication application)
        {
            EventLog.Debug("Initialising Detector Module");
            if ((Manager.Redirect != null) && Manager.Redirect.Enabled)
            {
                this._mobileHomePageUrl = Manager.Redirect.MobileHomePageUrl;
                this._firstRequestOnly = Manager.Redirect.FirstRequestOnly;
                if (!string.IsNullOrEmpty(Manager.Redirect.MobilePagesRegex))
                {
                    this._mobilePageRegex = new Regex(Manager.Redirect.MobilePagesRegex, RegexOptions.Compiled | RegexOptions.IgnoreCase);
                }
                this._formsLoginUrl = FormsAuthentication.LoginUrl;
            }
            this._clientTargets = this.GetClientTargets();
            application.BeginRequest += new EventHandler(this.OnBeginRequest);
            application.PostAcquireRequestState += new EventHandler(this.OnPostAcquireRequestState);
            application.PreRequestHandlerExecute += new EventHandler(this.OnPreRequestHandlerExecuteMobilePage);
            if (this._clientTargets != null)
            {
                application.PreRequestHandlerExecute += new EventHandler(this.OnPreRequestHandlerExecuteSetClientTargets);
            }
        }

        internal static bool IsFirstTime(HttpContext context, bool firstRequestOnly)
        {
            if (firstRequestOnly)
            {
                if ((context.Request.UrlReferrer != null) && (context.Request.UrlReferrer.Host == context.Request.Url.Host))
                {
                    return false;
                }
                if ((context.Session != null) && (context.Session["51dIsFirstRequest"] != null))
                {
                    context.Session["51dIsFirstRequest"] = false;
                    if (context.Request.Cookies["51D"] != null)
                    {
                        context.Response.Cookies.Remove("51D");
                    }
                    return false;
                }
                if (context.Request.Cookies["51D"] != null)
                {
                    return false;
                }
                if (RequestHistory.IsPresent(context.Request))
                {
                    return false;
                }
                if (context.Session != null)
                {
                    context.Session["51dIsFirstRequest"] = true;
                }
                if (!new List<string>(context.Response.Cookies.AllKeys).Contains("51D"))
                {
                    HttpCookie cookie = new HttpCookie("51D");
                    if (context.Session != null)
                    {
                        cookie.Expires = DateTime.UtcNow.AddMinutes((double) context.Session.Timeout);
                    }
                    else if (Manager.Redirect != null)
                    {
                        cookie.Expires = DateTime.UtcNow.AddMinutes((double) Manager.Redirect.Timeout);
                    }
                    context.Response.Cookies.Add(cookie);
                }
            }
            return true;
        }

        private static bool IsInArray(string value, string[] array)
        {
            foreach (string str in array)
            {
                if (value == str)
                {
                    return true;
                }
            }
            return false;
        }

        private bool IsMobilePage(HttpContext context)
        {
            return (IsMobileType(context.Handler.GetType()) || this.IsMobileRegexPage(context.Request));
        }

        private bool IsMobileRegexPage(HttpRequest request)
        {
            return ((this._mobilePageRegex != null) && this._mobilePageRegex.IsMatch(request.AppRelativeCurrentExecutionFilePath));
        }

        private static bool IsMobileType(Type type)
        {
            if (type != null)
            {
                if (IsInArray(type.FullName, MOBILE_PAGES))
                {
                    return true;
                }
                if (type.BaseType != null)
                {
                    return IsMobileType(type.BaseType);
                }
            }
            return false;
        }

        private static bool IsPage(HttpContext context)
        {
            return ((context.Handler != null) && IsPageType(context.Handler.GetType()));
        }

        private static bool IsPageType(Type type)
        {
            if (type != null)
            {
                if (IsInArray(type.FullName, PAGES))
                {
                    return true;
                }
                if (type.BaseType != null)
                {
                    return IsPageType(type.BaseType);
                }
            }
            return false;
        }

        private bool IsRedirectPage(HttpContext context)
        {
            return this._mobileHomePageUrl.Equals(context.Request.AppRelativeCurrentExecutionFilePath, StringComparison.InvariantCultureIgnoreCase);
        }

        private bool IsRestrictedPageForRedirect(HttpContext context)
        {
            Page handler = context.Handler as Page;
            if (handler != null)
            {
                string str = handler.ResolveUrl(context.Request.AppRelativeCurrentExecutionFilePath);
                return ((handler.ResolveUrl(this._mobileHomePageUrl) == str) || (handler.ResolveUrl(this._formsLoginUrl) == str));
            }
            return false;
        }

        public void OnBeginRequest(object sender, EventArgs e)
        {
            if (sender is HttpApplication)
            {
                HttpContext context = ((HttpApplication) sender).Context;
                if (context != null)
                {
                    try
                    {
                        OverrideCapabilities(context);
                    }
                    catch (NullReferenceException exception)
                    {
                        StringBuilder builder = new StringBuilder("A Null Exception occured which has the following header info:");
                        foreach (string str in context.Request.Headers.Keys)
                        {
                            builder.Append(Environment.NewLine).Append(str).Append("=").Append(context.Request.Headers[str]);
                        }
                        EventLog.Fatal(new MobileException(builder.ToString(), exception));
                    }
                }
            }
        }

        public void OnPostAcquireRequestState(object sender, EventArgs e)
        {
            if (sender is HttpApplication)
            {
                HttpContext context = ((HttpApplication) sender).Context;
                if ((context != null) && (((((context.Handler != null) && !string.IsNullOrEmpty(this._mobileHomePageUrl)) && (!this.IsRedirectPage(context) && IsPage(context))) && ((!this.IsMobilePage(context) && context.Request.Browser.IsMobileDevice) && IsFirstTime(context, this._firstRequestOnly))) && !this.IsRestrictedPageForRedirect(context)))
                {
                    string url = null;
                    if (!string.IsNullOrEmpty(context.Request.QueryString.ToString()))
                    {
                        url = string.Format("{0}?{1}", this._mobileHomePageUrl, context.Request.QueryString.ToString());
                    }
                    else
                    {
                        url = this._mobileHomePageUrl;
                    }
                    context.Response.Redirect(url, true);
                }
            }
        }

        public void OnPreInitPage(object sender, EventArgs e)
        {
            Page page = sender as Page;
            string str = null;
            if ((page != null) && this._clientTargets.TryGetValue(page.ClientTarget, out str))
            {
                OverrideCapabilities(page.Request, str);
            }
        }

        public void OnPreRequestHandlerExecuteMobilePage(object sender, EventArgs e)
        {
            if (sender is HttpApplication)
            {
                HttpContext context = ((HttpApplication) sender).Context;
                if ((context.Handler is MobilePage) && ("html4" == (context.Request.Browser.Capabilities["preferredRenderingType"] as string)))
                {
                    context.Request.Browser.Capabilities["preferredRenderingType"] = "html32";
                }
            }
        }

        public void OnPreRequestHandlerExecuteSetClientTargets(object sender, EventArgs e)
        {
            if (sender is HttpApplication)
            {
                HttpContext context = ((HttpApplication) sender).Context;
                if ((context != null) && (context.Handler is Page))
                {
                    ((Page) context.Handler).PreInit += new EventHandler(this.OnPreInitPage);
                }
            }
        }

        private static void OverrideCapabilities(HttpContext context)
        {
            if (!(context.Request.Browser is MobileCapabilities))
            {
                bool flag = Devices.IsMobileDevice(context);
                flag = true;
                if (flag || (flag != context.Request.Browser.IsMobileDevice))
                {
                    MobileCapabilities capabilities = Devices.Create(context);
                    if (capabilities != null)
                    {
                        context.Request.Browser = capabilities;
                    }
                }
            }
        }

        private static void OverrideCapabilities(HttpRequest request, string userAgent)
        {
            MobileCapabilities capabilities = Devices.Create(userAgent);
            if (capabilities != null)
            {
                request.Browser = capabilities;
            }
        }
    }
}

